package com.lukstron.youko;

import java.util.ArrayList;

import android.content.Context;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ListView;
import android.widget.ProgressBar;
import android.widget.Spinner;
import android.widget.TextView;

public class TestActivity extends YoukoActivity {

	/**
	 * Thread to handle test operation.
	 */
	protected StartThread _startThread = null;

	/**
	 * Contents of log list view.
	 */
	protected ArrayList<String> _logList = new ArrayList<String>();

	/**
	 * Adapter of log list view.
	 */
	protected ArrayAdapter<String> _logAdapter = null;

	/**
	 * Handler for updating UI invoking from StartThread.
	 * 
	 * We will only have 1 handler right?
	 */
	protected Handler _handler = new Handler() {

		@Override
		public void handleMessage(Message message) {
			Bundle bundle = message.getData();
			String string = null;
			string = bundle.getString("progress");
			if (string != null) {
				setProgress(string);
			}
			string = bundle.getString("log");
			if (string != null) {
				addLog(string);
			}
		}

	};

	/**
	 * Restore view to idle state in UI thread.
	 */
	protected Runnable _idling = new Runnable() {
		public void run() {
			idle();
		}
	};

	protected class StartThread extends Thread {

		public final static String MODE_AUTOMATIC = "automatic";
		public final static String MODE_MANUAL = "manual";

		protected Boolean _stopped = null;
		protected Hardware _hardware = null;
		protected Integer _channelOne = null;
		protected Integer _channelTwo = null;
		protected String _mode = null;

		public StartThread(Hardware hardware, String mode, Integer channelOne,
				Integer channelTwo) {
			_hardware = hardware;
			_mode = mode;
			_channelOne = channelOne;
			_channelTwo = channelTwo;
		}

		@Override
		public void run() {
			if (_hardware.connect()) {
				if (_mode == MODE_AUTOMATIC) {
					_testRange(_channelOne, _channelTwo);
				} else {
					_test(_channelOne, _channelTwo);
				}
				_hardware.disconnect();
			}
			TestActivity.this._handler.post(TestActivity.this._idling);
		}

		protected void _test(int primary, int secondary) {

		}

		protected void _testRange(int first, int last) {
			_stopped = false;
			StringBuilder stringBuilder = null;
			Boolean[] channels = new Boolean[last + 1];

			for (int channel = first; channel <= last; channel++) {
				stringBuilder = new StringBuilder();
				stringBuilder.append("Testing probe #");
				stringBuilder.append(channel);
				stringBuilder.append("...");
				_sendString("progress", stringBuilder.toString());

				for (int step = 1; step <= 3; step++) {
					int prior = channel - step;
					if (prior >= first && channels[prior]) {
						channels[channel] = _testConnectivity(channel, prior);
					}
					if (channels[channel]) {
						break;
					}

					int later = channel + step;
					if (later <= last) {
						channels[channel] = _testConnectivity(channel, later);
					}
					if (channels[channel]) {
						break;
					}
				}

				stringBuilder = new StringBuilder();
				if (channels[channel]) {
					stringBuilder.append("Probe #");
					stringBuilder.append(channel);
					stringBuilder.append(" OK");
				} else {
					if (_testAbRelay(channel)) {
						if (_testMnRelay(channel)) {
							stringBuilder.append("Probe #");
							stringBuilder.append(channel);
							stringBuilder.append(" Error");
						} else {
							stringBuilder.append("Relay Error (Channel #");
							stringBuilder.append(channel);
							stringBuilder.append(" MN)");
						}
					} else {
						stringBuilder.append("Relay Error (Channel #");
						stringBuilder.append(channel);
						stringBuilder.append(" AB)");
					}
				}

				_sendString("log", stringBuilder.toString());

				if (_stopped) {
					break;
				}
			}
		}

		protected Boolean _testAbRelay(int channel) {
			Datum datum = new Datum();
			datum.a = channel;
			datum.b = channel;
			return _hardware.test(datum);
		}

		protected Boolean _testMnRelay(int channel) {
			Datum datum = new Datum();
			datum.m = channel;
			datum.n = channel;
			return _hardware.test(datum);
		}

		protected Boolean _testConnectivity(int channelOne, int channelTwo) {
			Boolean result = _testAbConnectivity(channelOne, channelTwo);
			if (result) {
				result = _testMnConnectivity(channelOne, channelTwo);
			}
			return result;
		}

		protected Boolean _testAbConnectivity(int a, int b) {
			Datum datum = new Datum();
			datum.a = a;
			datum.b = b;
			return _hardware.test(datum);
		}

		protected Boolean _testMnConnectivity(int m, int n) {
			Datum datum = new Datum();
			datum.m = m;
			datum.n = n;
			return _hardware.test(datum);
		}

		@Override
		public void interrupt() {
			_stopped = true;
		}

		/**
		 * Send string to handler for show in view.
		 * 
		 * @param key
		 * @param value
		 */
		protected void _sendString(String key, String value) {
			Message message = null;
			Bundle bundle = null;
			bundle = new Bundle();
			bundle.putString(key, value);
			message = new Message();
			message.setData(bundle);
			TestActivity.this._handler.sendMessage(message);
		}

	}

	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.test);
		_initLog();
		_initMode();
		_readSetting();
		_bindStart();
		_bindStop();
		setView("idle");
	}

	@Override
	protected void onPause() {
		super.onPause();
		if (_startThread != null && _startThread.isAlive()) {
			_startThread.interrupt();
		}
	}

	/**
	 * Initialize log list view.
	 */
	protected void _initLog() {
		int i = R.layout.simple_list_item_1;
		_logAdapter = new ArrayAdapter<String>(this, i, _logList);
		ListView view = (ListView) findViewById(R.id.log);
		view.setAdapter(_logAdapter);
	}

	/**
	 * Initialize mode spinner.
	 */
	protected void _initMode() {
		ArrayAdapter<CharSequence> adapter = null;
		int arrayId = R.array.test_modes;
		int viewId = android.R.layout.simple_spinner_item;
		adapter = ArrayAdapter.createFromResource(this, arrayId, viewId);
		int resource = android.R.layout.simple_spinner_dropdown_item;
		adapter.setDropDownViewResource(resource);
		Spinner spinner = (Spinner) findViewById(R.id.mode);
		spinner.setAdapter(adapter);
	}

	protected void _readSetting() {
		Integer integer = null;
		SharedPreferences pref = null;
		EditText editText = null;

		pref = getSharedPreferences("GeoRes", Context.MODE_PRIVATE);

		editText = (EditText) findViewById(R.id.probe1);
		editText.setText("1");

		editText = (EditText) findViewById(R.id.probe2);
		integer = pref.getInt("electrode", 16);
		editText.setText(integer.toString());
	}

	/**
	 * Bind start button to event.
	 */
	protected void _bindStart() {
		Button button = (Button) findViewById(R.id.start);
		OnClickListener listener = null;
		listener = new OnClickListener() {
			public void onClick(View v) {
				start();
			}
		};
		button.setOnClickListener(listener);
	}

	/**
	 * Start test operation and turn off auto sleep.
	 */
	public void start() {
		acquireWakeLock();
		setView("start");
		Hardware hardware = new HardwareSimulator();
		String mode = StartThread.MODE_AUTOMATIC;
		_startThread = new StartThread(hardware, mode, 1, 16);
		_startThread.start();
	}

	/**
	 * Bind stop button to event.
	 */
	protected void _bindStop() {
		Button button = (Button) findViewById(R.id.stop);
		OnClickListener listener = null;
		listener = new OnClickListener() {
			public void onClick(View v) {
				stop();
			}
		};
		button.setOnClickListener(listener);
	}

	/**
	 * Abort test operation.
	 */
	public void stop() {
		setView("stop");
		_startThread.interrupt();
	}

	/**
	 * Set view to idle state and restore auto sleep.
	 * 
	 * This function must be called when thread finished whether operation
	 * complete or aborted.
	 */
	public void idle() {
		releaseWakeLock();
		setView("idle");
	}

	/**
	 * Set view as appropriate.
	 * 
	 * @param mode
	 *            [idle|start|stop]
	 */
	public void setView(String mode) {
		Button start = (Button) findViewById(R.id.start);
		Button stop = (Button) findViewById(R.id.stop);
		ProgressBar progressBar = (ProgressBar) findViewById(R.id.progressBar);
		TextView progressText = (TextView) findViewById(R.id.progressText);

		if (mode == "idle") {
			progressBar.setVisibility(View.GONE);
			progressText.setVisibility(View.GONE);
			start.setEnabled(true);
			stop.setEnabled(false);
		} else if (mode == "start") {
			progressBar.setVisibility(View.VISIBLE);
			progressText.setText("Initializing, please wait...");
			progressText.setVisibility(View.VISIBLE);
			start.setEnabled(false);
			stop.setEnabled(true);
		} else if (mode == "stop") {
			start.setEnabled(true);
			progressText.setText("Attempting to stop, please wait...");
		} else {

		}
	}

	/**
	 * Add new log and refresh the view.
	 */
	public void addLog(String log) {
		_logList.add(log);
		_logAdapter.notifyDataSetChanged();
	}

	/**
	 * Set progress text view.
	 * 
	 * @param progress
	 */
	public void setProgress(String progress) {
		TextView progressText = (TextView) findViewById(R.id.progressText);
		progressText.setText(progress);
	}

}
